package ui.panels.commands;

import java.io.*;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

import Data.ConfigurationParameters;
import auxiliary.AuxiliaryClass;

import ui.flowManager.FlowManagerImpl;
import ui.flowManager.expirimentProperties.AdditionalSettings;
import ui.flowManager.expirimentProperties.AgentRepresentation;
import ui.flowManager.expirimentProperties.ExperimentProperties;
import ui.flowManager.expirimentProperties.ExperimentProperties.Agent_Group;

/** 
 * @author vladimir && alon
 *
 *	The command save the experiment to XML file
 */
public class SaveToXMLCommand implements Command{

	private File file = null;
	
	public void execute() 
	{
		
		//case the file not updated
		if(file == null){
			return;
		}			
		
		//take the properties
		ExperimentProperties props = FlowManagerImpl.getInstance().getProps();
		try {
			  
			DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
		 
			// root elements
			Document doc = docBuilder.newDocument();
			Element root = doc.createElement("Experiment");
			doc.appendChild(root);

			//add the name of the experiment
			Element name = doc.createElement("ExperimentName");
			name.appendChild(doc.createTextNode(props.getExperimentName()));
			root.appendChild(name);
			
			int numGames = props.getNumOfGames();		
			// loop over the games
			for(int i = 1; i <= numGames; ++i)
			{
				//create the game element with his number as attribute
				Element game = doc.createElement("Game");
				Attr 	attr = doc.createAttribute("number");
				attr.setValue(Integer.toString(i));
				game.setAttributeNode(attr);
				
				//number of turns in the game
				Element numTurns = doc.createElement("NunberOfTurns");
				numTurns.appendChild(doc.createTextNode(Integer.toString(props.getNumOfTurns(i))));
				game.appendChild(numTurns);

				//number of repeats in the game
				Element numRepeats = doc.createElement("NunberOfRepeats");
				numRepeats.appendChild(doc.createTextNode(Integer.toString(props.getNumOfRepeats(i))));
				game.appendChild(numRepeats);
				
				//Observation
				Element observation = doc.createElement("Observation");
				observation.appendChild(doc.createTextNode(props.getObservationType(i)));
				game.appendChild(observation);
				
				// Create the players
				Element stidiedPlayers = createPlayers(doc, i, props,Agent_Group.STUDIED_AGENT);
				game.appendChild(stidiedPlayers);
				Element controlPlayers = createPlayers(doc, i, props,Agent_Group.CONTROL_AGENT);
				game.appendChild(controlPlayers);
				//put the game under experiment
				root.appendChild(game);
			}
			
			
			OutputFormat format = new OutputFormat(doc);
			format.setIndenting(true);
		    format.setLineSeparator(System.getProperty("line.separator")); 

		    //the path and the format of the file that created
			XMLSerializer serializer = 
				      new XMLSerializer(new FileOutputStream(file), format);
				
			//save the file
			serializer.serialize(doc);
			//System.out.println("File saved!");
			
		}
		//end try
		catch(ParserConfigurationException pce)
		{
			pce.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	
	public void setFile(File file) {
		this.file = file;
	}


	/**
	 * Create && return all the players of the game
	 * @param doc
	 * @param gameNumber
	 * @param props
	 * @return players
	 */
	private Element createPlayers(Document doc, int gameNumber, ExperimentProperties props, Agent_Group group)
	{
		Element players = null;
		
		if(group == Agent_Group.CONTROL_AGENT)
			players = doc.createElement("ControlPlayers");
		else
			players = doc.createElement("StudiedPlayers");
			
		int numPlayers = props.getNumOfPlayers(gameNumber, group);
		//loop over the players
		for(int j = 1; j <= numPlayers; ++j)
		{
			AgentRepresentation player= props.getPlayer(gameNumber, j, group);					
			//create the player element
			Element playerElement = createPlayerElement(doc, player);		
			//put the player under the players
			players.appendChild(playerElement);
		}
		
		return players;
	}

	
	/**
	 * Create && return element of player for XML 
	 * @param doc
	 * @param player
	 * @return playerElement
	 */
	private Element createPlayerElement(Document doc, AgentRepresentation player)
	{
		Element playerElement = doc.createElement("Player");
			
		//ID meanwhile - 0
		Element id = doc.createElement("ID");
		id.appendChild(doc.createTextNode(Integer.toString(player.getID())));
		playerElement.appendChild(id);
		
		//Team model
		Element teammateModel = doc.createElement(ConfigurationParameters.TeammateModel.TEAMMATE_MODEL);
		teammateModel.appendChild(doc.createTextNode(player.getTeammateModelType()));
		playerElement.appendChild(teammateModel);
		
		//Analyzer
		Element analyzer = doc.createElement(ConfigurationParameters.Analyzer.ANALYZER);
		analyzer.appendChild(doc.createTextNode(player.getAnalyzerType()));
		playerElement.appendChild(analyzer);
		
		//epsilon
		Element epsilon = doc.createElement("Epsilon");
		epsilon.appendChild(doc.createTextNode(Double.toString(player.getEpsilon())));
		playerElement.appendChild(epsilon);
		
		//competence
		Element competence = doc.createElement("Competence");
		competence.appendChild(doc.createTextNode(Double.toString(player.getCompetence())));
		playerElement.appendChild(competence);
				
		//distribution
		Element distribution = player.getDistributionType().getXMLElement(doc); 
		playerElement.appendChild(distribution);
		
		
		//strategy
		Element strategy = player.getStrategyType().getXMLElement(doc);
		playerElement.appendChild(strategy);
				
		Element additionalSettings = createAdditionalSettings(doc, player);
		playerElement.appendChild(additionalSettings);
		
		return playerElement;
	}
	
	private Element createAdditionalSettings(Document doc, AgentRepresentation player)
	{
		Element additionalSetElement = doc.createElement("AdditionalSettings");
		AdditionalSettings additionalSettings = player.getAdditionalSettings();
		Element haveElement = doc.createElement("Have");
		
		//case the player have not additional Settings
		if(additionalSettings == null)
		{
			haveElement.appendChild(doc.createTextNode("False"));
			additionalSetElement.appendChild(haveElement);
		}
		//case the player have additional Settings
		else
		{
			haveElement.appendChild(doc.createTextNode("True"));
			additionalSetElement.appendChild(haveElement);
			
			//for log
			Element logElement = doc.createElement("Log");
			String flagLog;
			//case have to log the player
			if(additionalSettings.isLog())
				flagLog = "True";
			else
				flagLog = "False";
			
			logElement.appendChild(doc.createTextNode(flagLog));
			additionalSetElement.appendChild(logElement);
			
			//for stop
			Element stopElement = doc.createElement("ToStop");
			String toStop;
			//case have to log the player
			if(additionalSettings.isStopAutomatically())
				toStop = "True";
			else
				toStop = "False";
			
			stopElement.appendChild(doc.createTextNode(toStop));
			additionalSetElement.appendChild(stopElement);	
		}
		
		return additionalSetElement;
	}
	 
}
